/*
 * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
 * Description: 循环缓冲区实现 - 用于音频数据的环形缓冲管理
 */

#include "little_test.h"
#include "osal_debug.h"
#include "securec.h"
#include <stdlib.h>
#include <string.h>

/**
 * @brief 初始化循环缓冲区
 * @param cb 循环缓冲区指针
 * @param size 缓冲区大小（样本数）
 * @return 0成功，其他失败
 */
int circular_buffer_init(circular_buffer_t *cb, uint32_t size)
{
    if (cb == NULL || size == 0) {
        osal_printk("[CIRCULAR_BUFFER] Invalid parameters\n");
        return -1;
    }

    // 分配缓冲区内存
    cb->buffer = (int16_t *)malloc(size * sizeof(int16_t));
    if (cb->buffer == NULL) {
        osal_printk("[CIRCULAR_BUFFER] Failed to allocate buffer memory\n");
        return -1;
    }

    // 创建信号量
    cb->sem_read = osal_sem_create(0);  // 初始无数据可读
    if (cb->sem_read == NULL) {
        osal_printk("[CIRCULAR_BUFFER] Failed to create read semaphore\n");
        free(cb->buffer);
        return -1;
    }

    cb->sem_write = osal_sem_create(size);  // 初始可写入size个样本
    if (cb->sem_write == NULL) {
        osal_printk("[CIRCULAR_BUFFER] Failed to create write semaphore\n");
        osal_sem_delete(cb->sem_read);
        free(cb->buffer);
        return -1;
    }

    // 初始化缓冲区状态
    cb->size = size;
    cb->write_index = 0;
    cb->read_index = 0;
    cb->is_full = false;

    // 清零缓冲区
    memset_s(cb->buffer, size * sizeof(int16_t), 0, size * sizeof(int16_t));

    osal_printk("[CIRCULAR_BUFFER] Initialized buffer with size %u samples\n", size);
    return 0;
}

/**
 * @brief 反初始化循环缓冲区
 * @param cb 循环缓冲区指针
 */
void circular_buffer_deinit(circular_buffer_t *cb)
{
    if (cb == NULL) {
        return;
    }

    // 释放信号量
    if (cb->sem_read != NULL) {
        osal_sem_delete(cb->sem_read);
        cb->sem_read = NULL;
    }

    if (cb->sem_write != NULL) {
        osal_sem_delete(cb->sem_write);
        cb->sem_write = NULL;
    }

    // 释放缓冲区内存
    if (cb->buffer != NULL) {
        free(cb->buffer);
        cb->buffer = NULL;
    }

    // 重置状态
    cb->size = 0;
    cb->write_index = 0;
    cb->read_index = 0;
    cb->is_full = false;

    osal_printk("[CIRCULAR_BUFFER] Buffer deinitialized\n");
}

/**
 * @brief 向循环缓冲区写入数据
 * @param cb 循环缓冲区指针
 * @param data 要写入的数据
 * @param size 数据大小（样本数）
 * @return 实际写入的样本数，负数表示错误
 */
int circular_buffer_write(circular_buffer_t *cb, const int16_t *data, uint32_t size)
{
    if (cb == NULL || data == NULL || size == 0) {
        return -1;
    }

    uint32_t written = 0;
    uint32_t to_write = size;

    while (written < size) {
        // 等待写入空间可用
        if (osal_sem_wait(cb->sem_write, OSAL_WAIT_FOREVER) != OSAL_SUCCESS) {
            osal_printk("[CIRCULAR_BUFFER] Write semaphore wait failed\n");
            break;
        }

        // 计算可写入的数据量
        uint32_t available = circular_buffer_available_write(cb);
        uint32_t chunk_size = (to_write > available) ? available : to_write;
        
        if (chunk_size == 0) {
            osal_sem_signal(cb->sem_write);  // 释放信号量
            break;
        }

        // 写入数据
        for (uint32_t i = 0; i < chunk_size; i++) {
            cb->buffer[cb->write_index] = data[written + i];
            cb->write_index = (cb->write_index + 1) % cb->size;
            
            // 检查是否满了
            if (cb->write_index == cb->read_index) {
                cb->is_full = true;
            }
        }

        written += chunk_size;
        to_write -= chunk_size;

        // 通知有数据可读
        for (uint32_t i = 0; i < chunk_size; i++) {
            osal_sem_signal(cb->sem_read);
        }
    }

    return (int)written;
}

/**
 * @brief 从循环缓冲区读取数据
 * @param cb 循环缓冲区指针
 * @param data 读取数据的缓冲区
 * @param size 要读取的数据大小（样本数）
 * @return 实际读取的样本数，负数表示错误
 */
int circular_buffer_read(circular_buffer_t *cb, int16_t *data, uint32_t size)
{
    if (cb == NULL || data == NULL || size == 0) {
        return -1;
    }

    uint32_t read_count = 0;
    uint32_t to_read = size;

    while (read_count < size) {
        // 等待数据可读
        if (osal_sem_wait(cb->sem_read, OSAL_WAIT_FOREVER) != OSAL_SUCCESS) {
            osal_printk("[CIRCULAR_BUFFER] Read semaphore wait failed\n");
            break;
        }

        // 计算可读取的数据量
        uint32_t available = circular_buffer_available_read(cb);
        uint32_t chunk_size = (to_read > available) ? available : to_read;
        
        if (chunk_size == 0) {
            osal_sem_signal(cb->sem_read);  // 释放信号量
            break;
        }

        // 读取数据
        for (uint32_t i = 0; i < chunk_size; i++) {
            data[read_count + i] = cb->buffer[cb->read_index];
            cb->read_index = (cb->read_index + 1) % cb->size;
            
            // 缓冲区不再满
            if (cb->is_full) {
                cb->is_full = false;
            }
        }

        read_count += chunk_size;
        to_read -= chunk_size;

        // 通知有空间可写
        for (uint32_t i = 0; i < chunk_size; i++) {
            osal_sem_signal(cb->sem_write);
        }
    }

    return (int)read_count;
}

/**
 * @brief 检查循环缓冲区是否满
 * @param cb 循环缓冲区指针
 * @return true满，false不满
 */
bool circular_buffer_is_full(const circular_buffer_t *cb)
{
    if (cb == NULL) {
        return false;
    }
    return cb->is_full;
}

/**
 * @brief 检查循环缓冲区是否空
 * @param cb 循环缓冲区指针
 * @return true空，false不空
 */
bool circular_buffer_is_empty(const circular_buffer_t *cb)
{
    if (cb == NULL) {
        return true;
    }
    return (!cb->is_full && (cb->read_index == cb->write_index));
}

/**
 * @brief 获取可写入的空间大小
 * @param cb 循环缓冲区指针
 * @return 可写入的样本数
 */
uint32_t circular_buffer_available_write(const circular_buffer_t *cb)
{
    if (cb == NULL) {
        return 0;
    }

    if (cb->is_full) {
        return 0;
    }

    if (cb->write_index >= cb->read_index) {
        return cb->size - (cb->write_index - cb->read_index);
    } else {
        return cb->read_index - cb->write_index;
    }
}

/**
 * @brief 获取可读取的数据大小
 * @param cb 循环缓冲区指针
 * @return 可读取的样本数
 */
uint32_t circular_buffer_available_read(const circular_buffer_t *cb)
{
    if (cb == NULL) {
        return 0;
    }

    if (cb->is_full) {
        return cb->size;
    }

    if (cb->write_index >= cb->read_index) {
        return cb->write_index - cb->read_index;
    } else {
        return cb->size - (cb->read_index - cb->write_index);
    }
}